#ifndef Array1D_
#define Array1D_

#include <iostream>

#include "AlogException.h"


template<class T>
class Array1D {
  public:
    Array1D( int size = 0 );
    Array1D( const Array1D<T>& v );
    ~Array1D() { delete [] element; }

    int Size() { return size; }
    Array1D<T>& ReSize( int sz );

    T& operator[]( int i ) const;
    Array1D<T>& operator=( const Array1D<T>& v );
    Array1D<T> operator+() const;
    Array1D<T> operator+( const Array1D<T>& v ) const;
    Array1D<T> operator-() const;
    Array1D<T> operator-( const Array1D<T>& v ) const;
    Array1D<T> operator*( const Array1D<T>& v ) const;
    Array1D<T>& operator+=( const T& x );

    void Output( std::ostream& out ) const;

  private:
    int size;
    T *element;
};



template<class T>
Array1D<T>::Array1D( int sz /*= 10 */)
{
    if ( sz < 0 ) throw BadInitializers();

    size = sz;
    element = new T[sz];
}

template<class T>
Array1D<T>::Array1D( const Array1D<T>& v )
{
    size = v.size;
    element = new T[size];

    for ( int i = 0; i < size; i++ )
        element[i] = v.element[i];
}

template<class T>
T& Array1D<T>::operator[](int i) const
{
    if ( i < 0 || i >= size ) throw OutOfBounds();

    return element[i];
}

template<class T>
Array1D<T>& Array1D<T>::operator=(const Array1D<T>& v)
{
    if ( this != &v ) {
        size = v.size;
        delete [] element;
        element = new T[size];
        for ( int i = 0; i < size; i++ )
            element[i] = v.element[i];
      }

    return *this;
}

template<class T>
Array1D<T> Array1D<T>::operator+( const Array1D<T>& v ) const
{
    if ( size != v.size ) throw SizeMismatch();

    Array1D<T> w( size );

    for ( int i = 0; i < size; i++ )
        w.element[i] = element[i] + v.element[i];

    return w;
}

template<class T>
Array1D<T> Array1D<T>::operator-( const Array1D<T>& v ) const
{
    if ( size != v.size ) throw SizeMismatch();

    Array1D<T> w( size );
    for ( int i = 0; i < size; i++ )
        w.element[i] = element[i] - v.element[i];

    return w;
}

template<class T>
Array1D<T> Array1D<T>::operator-() const
{
    Array1D<T> w( size );

    for ( int i = 0; i < size; i++ )
        w.element[i] = -element[i];

    return w;
}

template<class T>
Array1D<T> Array1D<T>::operator*( const Array1D<T>& v ) const
{
    if ( size != v.size ) throw SizeMismatch();

   Array1D<T> w( size );

   for ( int i = 0; i < size; i++ )
        w.element[i] = element[i] * v.element[i];

    return w;
}

template<class T>
Array1D<T>& Array1D<T>::operator+=(const T& x)
{
    for ( int i = 0; i < size; i++ )
        element[i] += x;

    return *this;
}

template<class T>
Array1D<T>& Array1D<T>::ReSize( int sz )
{
   if (sz < 0) throw BadInitializers();

    delete [] element;

    size = sz;
    element = new T[size];

    return *this;
}

template<class T>
void Array1D<T>::Output( std::ostream& out ) const
{
    for ( int i = 0; i < size; i++ ) {
        out << element[i] << " ";
    }
}

template<class T>
std::ostream& operator<<( std::ostream& out, const Array1D<T>& x )
{
    x.Output( out );

    return out;
}

#endif

